<?php
/**
 * Created by PhpStorm.
 * User: ari
 * Date: 10/17/14
 * Time: 11:13 PM
 */
namespace BC\Games\Holdem\Hands;

use BC\Games\Holdem\Cards;
use BC\Games\Holdem\Deck;
use CPath\UnitTest\ITestable;
use CPath\UnitTest\IUnitTestRequest;

class StraightFlushHand implements IPokerHand, ITestable
{
	const RANK = 7000;

	private $mCards;

	public function __construct(Array $cards) {
		sort($cards);
		if($cards[4] & Cards::NUMBER_MASK === Cards::ACE) {
			array_unshift($cards, array_pop($cards));
		}
		$this->mCards = $cards;
	}

	/**
	 * Return name of this hand
	 * @return String
	 */
	function getName() {
		return "Straight Flush";
	}

	function getCards($withNullDelimiter=null) {
		return $this->mCards;
	}

	function getHighCard() {
		$card = 0;
		foreach($this->mCards as $c)
			if($c > $card)
				$card = $c;
		return $card;
	}

	/**
	 * Get Hand rank
	 * @return int
	 */
	function getRank() {
		return self::RANK
			+ ($this->getHighCard() & Cards::NUMBER_MASK);
	}

	/**
	 * Compare two hands
	 * @param IPokerHand $Hand
	 * @return int 0, <0, or >0
	 */
	function compare(IPokerHand $Hand) {
		$rank = $this->getRank() - $Hand->getRank();
		if (!$Hand instanceof StraightFlushHand)
			return $rank;

		foreach ($this->mCards as $i => $card) {
			$rank = $card - $Hand->mCards[$i];
			if ($rank !== 0)
				return $rank;
		}

		return 0;
	}

	/**
	 * Returns a string representation of this poker hand
	 * @return String
	 */
	function __toString() {
		$str = '[';
		foreach ($this->mCards as $i => $card) {
			$str .= ($i ? ', ' : '') . Cards::printCards($card);
		}

		return $str . ']';
	}

	// Static


	/**
	 * Tests a poker hand to see if it matches an array of cards
	 * @param array $cards
	 * @param IPokerHand[] $Matches
	 * @return bool true if the set of cards matches this poker hand
	 */
	static function match(Array $cards, &$Matches = array()) {
		$found = false;

		/** @var FlushHand[] $Flushes */
		if(FlushHand::match($cards, $Flushes)) {
			foreach($Flushes as $Flush) {

				/** @var StraightHand[] $Straights */
				if(StraightHand::match($Flush->getCards(false), $Straights)) {
					foreach($Straights as $Straight) {
						/** @var StraightHand $Straight */
						$highCard = $Straight->getHighCard() & Cards::NUMBER_MASK;
						if($highCard === Cards::ACE)
							$Matches[] = new RoyalFlushHand($Straight->getCards(false));
						else
							$Matches[] = new StraightFlushHand($Straight->getCards(false));
						$found = true;
					}
				}
			}
		}

		return $found;
	}

	/**
	 * Perform a unit test
	 * @param IUnitTestRequest $Test the unit test request inst for this test session
	 * @return void
	 * @test --disable 0
	 * Note: Use doctag 'test' with '--disable 1' to have this ITestable class skipped during a build
	 */
	static function handleStaticUnitTest(IUnitTestRequest $Test) {
		$Deck = new Deck();
		$Deck->replay(Cards::ACE | Cards::HEARTS, 'player1');
		$Deck->replay(Cards::FIVE | Cards::HEARTS, 'player1');
		$Deck->replay(Cards::THREE | Cards::HEARTS, 'board');
		$Deck->replay(Cards::FOUR | Cards::HEARTS, 'board');
		$Deck->replay(Cards::NINE | Cards::HEARTS, 'board');
		$Deck->replay(Cards::SEVEN | Cards::HEARTS, 'board');
		$Deck->replay(Cards::TWO | Cards::HEARTS, 'board');

		$cards = $Deck->getDrawnCards('player1', 'board');
		if (!StraightFlushHand::match($cards, $Hands))
			$Test->fail("Straight Flush not matched to cards: " . Cards::printCards($cards));

		$Test->log("Matched Straight Flush to " . $Hands[0] . ' from ' . Cards::printCards($cards), $Test::VERBOSE);
	}
}